﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;

namespace Hids.Classes
{
    /// <summary>
    /// This class holds the methods and properties used to ensure specific Registry Keys do not change
    /// </summary>
    class RegistryIntegrity
    {
        #region Private Properties

        private static Dictionary<String, String> registryValues;

        #endregion

        #region Private Methods

        /// <summary>
        /// This method recursively checks all SubKeys of a given register and then tests the values contained in those keys 
        /// against a preexisting image of the registery.  If report is true, it reports its findings. if it is false it will be silent 
        /// about any changes to the registry.
        /// </summary>
        /// <param name="register">An open register key to check</param>
        /// <param name="report">Whether or not to report the registry change</param>
        private static void CheckRegister(RegistryKey register, bool report)
        {
            if (register == null)
                return;

            foreach (string sub in register.GetSubKeyNames())
            {
                // Need to fail silently if there are security exceptions.
                try
                {
                    CheckRegister(register.OpenSubKey(sub), report);
                }
                catch (Exception e) { }
            }

            string regVal;

            foreach (string val in register.GetValueNames())
            {
                if (!registryValues.TryGetValue(register.ToString() + "\\" + val, out regVal))
                {
                    if (report)
                    {
                        string notificationMessage = "A registry addition has occured! \"" + register.ToString() + "\\" + val + "\" now equals \"" + 
                            register.GetValue(val).ToString() + "\"";
                        Logs.WriteMessageToLog(notificationMessage);
                        Notifications.SendEmail(notificationMessage);
                        Console.WriteLine(notificationMessage);
                    }

                    registryValues.Add(register.ToString() + "\\" + val, register.GetValue(val).ToString());
                } else if (regVal != register.GetValue(val).ToString())
                {
                    if (report)
                    {
                        string notificationMessage = "A registry change has occured! \"" + register.ToString() + "\\" + val + "\" used to equal \"" + regVal +
                            "\" now equals \"" + register.GetValue(val).ToString() + "\"";
                        Logs.WriteMessageToLog(notificationMessage);
                        Notifications.SendEmail(notificationMessage);
                        Console.WriteLine(notificationMessage);
                    }

                    registryValues.Remove(register.ToString() + "\\" + val);
                    registryValues.Add(register.ToString() + "\\" + val, register.GetValue(val).ToString());
                }
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// This method will check all registy entries in the list.
        /// The registry entries must branch from a root node or they will be discarded.
        /// If this is the first time the method is called it will construct an image of the registry for future calls.
        /// </summary>
        /// <param name="registersToCheck">The list of registry keys to check</param>
        public static void CheckRegisters(List<String> registersToCheck)
        {
            bool report = true;
            if (registryValues == null)
            {
                report = false;
                registryValues = new Dictionary<string,string>();
            }

            foreach (string register in registersToCheck)
            {
                if (register.StartsWith("HKEY_CLASSES_ROOT\\"))
                {
                    CheckRegister(Registry.ClassesRoot.OpenSubKey(register.Substring(18)), report);
                    continue;
                }

                if (register.StartsWith("HKEY_CURRENT_USER\\"))
                {
                    CheckRegister(Registry.CurrentUser.OpenSubKey(register.Substring(18)), report);
                    continue;
                }

                if (register.StartsWith("HKEY_LOCAL_MACHINE\\"))
                {
                    CheckRegister(Registry.LocalMachine.OpenSubKey(register.Substring(19)), report);
                    continue;
                }
                
                if (register.StartsWith("HKEY_USERS\\"))
                {
                    CheckRegister(Registry.Users.OpenSubKey(register.Substring(11)), report);
                    continue;
                }

                if (register.StartsWith("HKEY_CURRENT_CONFIG\\"))
                {
                    CheckRegister(Registry.CurrentConfig.OpenSubKey(register.Substring(20)), report);
                    continue;
                }
            }
        }

        #endregion
    }
}
